package lastRites.game.networking;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

import lastRites.enums.BlockType;
import lastRites.enums.TileSetName;
import lastRites.game.terrain.TerrainBlock;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryonet.Client;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import com.esotericsoftware.kryonet.Server;

public class MapSendTest extends KryoNetTestCase {
	public void testWholeMapSend() throws IOException {
		final TerrainBlock[][] map = new TerrainBlock[100][100];
		for( int i = 0; i < map.length; i++ ) {
			for( int j = 0; j < map[0].length; j++ ) {
				map[i][j] = new TerrainBlock( TileSetName.Terraria, BlockType.DIRT, i, j );
			}
		}

		Server server = new Server( 16384, 8192 );
		register( server.getKryo() );
		startEndPoint( server );
		server.bind( tcpPort, udpPort );
		server.addListener( new Listener() {
			@Override
			public void received(Connection connection, Object object) {
				if( object instanceof MapRequest ) {
					int tiles = 0;
					for( int i = 0; i < map.length; i++ ) {
						for( int j = 0; j < map[0].length; j++ ) {
							connection.sendTCP( new MapTile( map[i][j] ) );
							tiles++;
							System.out.println( "Sent " + tiles );
						}
					}
				}
			}
		} );

		Client client = new Client( 16384, 8192 );
		register( client.getKryo() );
		startEndPoint( client );
		final AtomicInteger tilesGot = new AtomicInteger( 0 );
		client.addListener( new Listener() {
			@Override
			public void connected(Connection connection) {
				System.out.println( "Client sending map request" );
				connection.sendTCP( new MapRequest() );
			}

			@Override
			public void received(Connection connection, Object object) {
				if( object instanceof MapPacket ) {
					MapPacket packet = (MapPacket)object;
					System.out.println( "Got a map! Map is " + packet.map[0].length + " wide by " + packet.map.length + " tall." );
				}
				if( object instanceof MapTile ) {
					TerrainBlock t = ( (MapTile)object ).tile;
					tilesGot.addAndGet( 1 );
					System.out.println( "Got tile: " + t.getRow() + ", " + t.getCol() + " - " + t.getTileImageName() + "_" + t.getWidth() + "x" + t.getHeight() );
					System.out.println( "Client recieved " + tilesGot + " tiles." );
				}
			}
		} );

		client.connect( 5000, host, tcpPort, udpPort );

		waitForThreads( 9000 );
		waitForThreads( 9000 );
	}

	public static class MapPacket {
		public TerrainBlock[][]	map;

		public MapPacket(TerrainBlock[][] m) {
			this.map = m;
		}
	}

	public static class MapTile {
		public TerrainBlock	tile;

		public MapTile() {}

		public MapTile(TerrainBlock e) {
			this.tile = e;
		}
	}

	public static class MapRequest {
		public MapRequest() {}
	}

	public static class MapTileConfirmation {
		public MapTileConfirmation() {}
	}

	private void register(Kryo kryo) {
		kryo.register( MapTileConfirmation.class );
		kryo.register( MapTile.class );
		kryo.register( MapRequest.class );
		kryo.register( MapPacket.class );
		kryo.register( TileSetName.class );
		kryo.register( TerrainBlock.class );
		kryo.register( TerrainBlock[].class );
		kryo.register( TerrainBlock[][].class );
	}
}
